// netstat -nap 查看服务

#ifndef _SERVER_HPP
#define _SERVER_HPP
#include "Common.hpp"

#include <iostream>
#include <string>
#include <memory>

// 套接字头文件
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

// 日志
#include "log.hpp"

#include <cstring>
#include <cerrno>

// 清零函数
#include <strings.h>

// 端口函数
#include <arpa/inet.h>

#include <cstdlib>

const static int GSOCKFD = -1;
// const static std::string GIP = "127.0.0.1"; // 本地的ip地址
const static uint16_t GPORT = 8080; // 端口号

class UDPServer
{
public:
    // UDPServer(const std::string _out_ip = GIP, uint16_t _out_port = GPORT)
    UDPServer(uint16_t _out_port = GPORT)
        : _sockfd(GSOCKFD),
          //   _ip(_out_ip),
          _port(_out_port),
          _isrunning(false)
    {
        // 创建套接字 SOCK_DGRAM 就是UDP
    }

    void Init()
    {
        // LOG::LOG(LOG::LogLevel::INFO) << "socket success!" << "the sockfd is " << _sockfd << "\n";

        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG::LOG(LOG::LogLevel::FATAL) << "socket: " << strerror(errno);
            // 创建失败！
            exit(1);
        }
        LOG::LOG(LOG::LogLevel::INFO) << "socket success!" << "the sockfd is " << _sockfd << "\n";

        // 填充网络信息 只是填充到结构体
        struct sockaddr_in _local;
        bzero(&_local, sizeof(_local));
        _local.sin_family = AF_INET;
        _local.sin_port = htons(_port); // 要被发送给的对方 也要发到网络中 还要把主机序列转成网络序列
                                        // _local.sin_addr.s_addr = inet_addr(_ip.c_str()); // 先把 字符串转成四字节； 再转成网络的！
        // 以上的代码就是把在栈上面作填充

        _local.sin_addr.s_addr = INADDR_ANY;

        // 绑定 才进入到结构体                                        //
        int _n = ::bind(_sockfd, CONV(&_local), sizeof(_local));
        if (_n < 0)
        {
            LOG::LOG(LOG::LogLevel::FATAL) << "bind:" << strerror(errno);
            exit(2);
        }

        LOG::LOG(LOG::LogLevel::INFO) << "bind success!" << "the sockfd is " << _sockfd << "\n";
    }
    // recvfrom 函数
    void Start()
    {
        _isrunning = true;
        while (true)
        {
            char _inbuffer[1024];
            struct sockaddr_in _peer;
            socklen_t _len = sizeof(_peer); // 这个是必须设定的

            // 这里-1 是为了 预留一个\n
            ssize_t _n = ::recvfrom(
                _sockfd,
                _inbuffer, sizeof(_inbuffer) - 1,
                0, CONV(&_peer), &_len);

            if (_n > 0) // 说明收到消息了
            {
                uint16_t _clientport = ::ntohs(_peer.sin_port);
                std::string _clientip = ::inet_ntoa(_peer.sin_addr);
                _inbuffer[_n] = 0; // 加上 \0

                std::string _clientinfo = _clientip + ":" + std::to_string(_clientport) + "# " + _inbuffer;

                LOG::LOG(LOG::LogLevel::DEBUG) << _clientinfo;

                std::string _echo = "echo# ";

                ::sendto(
                    _sockfd,
                    _echo.c_str(), _echo.size(),
                    0, CONV(&_peer), _len);
            }
        }
    }

private:
    int _sockfd; // 句柄  全双工 既可以收 也可以发

    uint16_t _port; // 端口号 2 字节

    // std::string _ip; // 服务器所对应的IP地址！ 4 字节

    bool _isrunning; // 服务器状态
};

#endif